<html><head><meta charset="utf-8"><title>20 this，类型？-慕课专栏</title>
			<meta http-equiv="X-UA-Compatible" content="IE=edge, chrome=1">
			<meta name="renderer" content="webkit">
			<meta property="qc:admins" content="77103107776157736375">
			<meta property="wb:webmaster" content="c4f857219bfae3cb">
			<meta http-equiv="Access-Control-Allow-Origin" content="*">
			<meta http-equiv="Cache-Control" content="no-transform ">
			<meta http-equiv="Cache-Control" content="no-siteapp">
			<link rel="apple-touch-icon" sizes="76x76" href="https://www.imooc.com/static/img/common/touch-icon-ipad.png">
			<link rel="apple-touch-icon" sizes="120x120" href="https://www.imooc.com/static/img/common/touch-icon-iphone-retina.png">
			<link rel="apple-touch-icon" sizes="152x152" href="https://www.imooc.com/static/img/common/touch-icon-ipad-retina.png">
			<link href="https://moco.imooc.com/captcha/style/captcha.min.css" rel="stylesheet">
			<link rel="stylesheet" href="https://www.imooc.com/static/moco/v1.0/dist/css/moco.min.css?t=201907021539" type="text/css">
			<link rel="stylesheet" href="https://www.imooc.com/static/lib/swiper/swiper-3.4.2.min.css?t=201907021539">
			<link rel="stylesheet" href="https://static.mukewang.com/static/css/??base.css,common/common-less.css?t=2.5,column/zhuanlanChapter-less.css?t=2.5,course/inc/course_tipoff-less.css?t=2.5?v=201907051055" type="text/css">
			<link charset="utf-8" rel="stylesheet" href="https://www.imooc.com/static/lib/ueditor/themes/imooc/css/ueditor.css?v=201907021539"><link rel="stylesheet" href="https://www.imooc.com/static/lib/baiduShare/api/css/share_style0_16.css?v=6aba13f0.css"></head>
			<body><div id="main">

<div class="container clearfix" id="top" style="display: block; width: 1134px;">
    
    <div class="center_con js-center_con l" style="width: 1134px;">
        <div class="article-con">
                            <!-- 买过的阅读 -->
                <div class="map">
                    <a href="/read" target="_blank"><i class="imv2-feather-o"></i></a>
                    <a href="/read/35" target="_blank">零基础学透 TypeScript</a>
                    <a href="" target="_blank">
                        <span>
                            / 3-7 20 this，类型？
                        </span>
                    </a>
                </div>

            


            <div class="art-title" style="margin-top: 0px;">
                20 this，类型？
            </div>
            <div class="art-info">
                
                <span>
                    更新时间：2019-06-27 18:00:07
                </span>
            </div>
            <div class="art-top">
                                <img src="https://img2.mukewang.com/5d0c39f60001fbf706400359.jpg" alt="">
                                                <div class="famous-word-box">
                    <img src="https://www.imooc.com/static/img/column/bg-l.png" alt="" class="bg1 bg">
                    <img src="https://www.imooc.com/static/img/column/bg-r.png" alt="" class="bg2 bg">
                    <div class="famous-word">每个人都是自己命运的主宰。<p class="author">——斯蒂尔斯</p></div>
                </div>
                            </div>
            <div class="art-content js-lookimg">
                <div><div class="cl-preview-section"><p style="font-size: 20px; line-height: 38px;">在 JavaScript 中，this 可以用来获取对全局对象、类实例对象、构建函数实例等的引用，在 TypeScript 中，this 也是一种类型，我们先来看个计算器 Counter 的例子：</p>
</div><div class="cl-preview-section"><pre class="  language-typescript"><code class="prism  language-typescript"><span class="token keyword">class</span> <span class="token class-name">Counter</span> <span class="token punctuation">{</span>
  <span class="token keyword">constructor</span><span class="token punctuation">(</span><span class="token keyword">public</span> count<span class="token punctuation">:</span> <span class="token keyword">number</span> <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token punctuation">}</span>
  <span class="token function">add</span><span class="token punctuation">(</span>value<span class="token punctuation">:</span> <span class="token keyword">number</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">// 定义一个相加操作的方法</span>
    <span class="token keyword">this</span><span class="token punctuation">.</span>count <span class="token operator">+=</span> value<span class="token punctuation">;</span>
    <span class="token keyword">return</span> <span class="token keyword">this</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
  <span class="token function">subtract</span><span class="token punctuation">(</span>value<span class="token punctuation">:</span> <span class="token keyword">number</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">// 定义一个相减操作的方法</span>
    <span class="token keyword">this</span><span class="token punctuation">.</span>count <span class="token operator">-=</span> value<span class="token punctuation">;</span>
    <span class="token keyword">return</span> <span class="token keyword">this</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
<span class="token keyword">let</span> counter <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Counter</span><span class="token punctuation">(</span><span class="token number">10</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>counter<span class="token punctuation">.</span>count<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 10</span>
counter<span class="token punctuation">.</span><span class="token function">add</span><span class="token punctuation">(</span><span class="token number">5</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">subtract</span><span class="token punctuation">(</span><span class="token number">2</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>counter<span class="token punctuation">.</span>count<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 13</span>
</code></pre>
</div><div class="cl-preview-section"><p style="font-size: 20px; line-height: 38px;">我们给 Counter 类定义几个方法，每个方法都返回 this，这个 this 即指向实例，这样我们就可以通过链式调用的形式来使用这些方法。这个是没有问题的，但是如果我们要通过类继承的形式丰富这个 Counter 类，添加一些方法，依然返回 this，然后采用链式调用的形式调用，在过去版本的 TypeScript 中是有问题的，先来看我们继承的逻辑：</p>
</div><div class="cl-preview-section"><pre class="  language-typescript"><code class="prism  language-typescript"><span class="token keyword">class</span> <span class="token class-name">PowCounter</span> <span class="token keyword">extends</span> <span class="token class-name">Counter</span> <span class="token punctuation">{</span>
  <span class="token keyword">constructor</span><span class="token punctuation">(</span><span class="token keyword">public</span> count<span class="token punctuation">:</span> <span class="token keyword">number</span> <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">super</span><span class="token punctuation">(</span>count<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
  <span class="token function">pow</span><span class="token punctuation">(</span>value<span class="token punctuation">:</span> <span class="token keyword">number</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">// 定义一个幂运算操作的方法</span>
    <span class="token keyword">this</span><span class="token punctuation">.</span>count <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span>count <span class="token operator">**</span> value<span class="token punctuation">;</span>
    <span class="token keyword">return</span> <span class="token keyword">this</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
<span class="token keyword">let</span> powcounter <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">PowCounter</span><span class="token punctuation">(</span><span class="token number">2</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
powCounter
  <span class="token punctuation">.</span><span class="token function">pow</span><span class="token punctuation">(</span><span class="token number">3</span><span class="token punctuation">)</span>
  <span class="token punctuation">.</span><span class="token function">subtract</span><span class="token punctuation">(</span><span class="token number">3</span><span class="token punctuation">)</span>
  <span class="token punctuation">.</span><span class="token function">add</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>powCounter<span class="token punctuation">.</span>count<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 6</span>
</code></pre>
</div><div class="cl-preview-section"><p style="font-size: 20px; line-height: 38px;">我们定义了 PowCounter 类，它继承 Counter 类，新增了 pow 方法用来求值的幂次方，这里我们使用了 ES7 新增的幂运算符<code>**</code>。我们使用 PowCounter 创建了实例 powcounter，它的类型自然是 PowCounter，在该实例上调用继承来的 subtract 和 add 方法。如果是在过去，就会报错，因为创建实例 powcounter 的类 PowCounter 没有定义这两个方法，所以会报没有这两个方法的错误。但是在 1.7 版本中增加了 this 类型，TypeScript 会对方法返回的 this 进行判断，就不会报错了。</p>
</div><div class="cl-preview-section"><p style="font-size: 20px; line-height: 38px;">对于对象来说，对象的属性值可以是一个函数，那么这个函数也称为方法，在方法内如果访问this，默认情况下是对这个对象的引用，this类型也就是这个对象的字面量类型，如下：</p>
</div><div class="cl-preview-section"><pre class="  language-typescript"><code class="prism  language-typescript"><span class="token comment">// 例3.7.1</span>
<span class="token keyword">let</span> info <span class="token operator">=</span> <span class="token punctuation">{</span>
  name<span class="token punctuation">:</span> <span class="token string">'Lison'</span><span class="token punctuation">,</span>
  <span class="token function">getName</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
      <span class="token keyword">return</span> <span class="token keyword">this</span><span class="token punctuation">.</span>name <span class="token comment">// "Lison" 这里this的类型为 { name: string; getName(): string; }</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre>
</div><div class="cl-preview-section"><p style="font-size: 20px; line-height: 38px;">但是如果显式地指定了this的类型，那么this的类型就改变了，如下：</p>
</div><div class="cl-preview-section"><pre class="  language-typescript"><code class="prism  language-typescript"><span class="token comment">// 例3.7.2</span>
<span class="token keyword">let</span> info <span class="token operator">=</span> <span class="token punctuation">{</span>
  name<span class="token punctuation">:</span> <span class="token string">"Lison"</span><span class="token punctuation">,</span>
  <span class="token function">getName</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">:</span> <span class="token punctuation">{</span> age<span class="token punctuation">:</span> <span class="token keyword">number</span> <span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">this</span><span class="token punctuation">;</span> <span class="token comment">// 这里的this的类型是{ age: number }</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>
</code></pre>
</div><div class="cl-preview-section"><p style="font-size: 20px; line-height: 38px;">如果我们在 tsconfig.json 里将 noImplicitThis 设为 true，这时候有两种不同的情况：</p>
</div><div class="cl-preview-section"><p style="font-size: 20px; line-height: 38px;">(1) 对象字面量具有 ThisType&lt;T&gt; 指定的类型，此时 this 的类型为 T，来看例子：</p>
</div><div class="cl-preview-section"><pre class="  language-typescript"><code class="prism  language-typescript"><span class="token keyword">type</span> ObjectDescriptor<span class="token operator">&lt;</span>D<span class="token punctuation">,</span> M<span class="token operator">&gt;</span> <span class="token operator">=</span> <span class="token punctuation">{</span> <span class="token comment">// 使用类型别名定义一个接口，这里用了泛型，两个泛型变量D和M</span>
  data<span class="token operator">?</span><span class="token punctuation">:</span> D<span class="token punctuation">;</span> <span class="token comment">// 这里指定data为可选字段，类型为D</span>
  <span class="token comment">// 这里指定methods为可选字段，类型为M和ThisType&lt;D &amp; M&gt;组成的交叉类型；  </span>
  <span class="token comment">// ThisType是一个内置的接口，用来在对象字面量中键入this，这里指定this的类型为D &amp; M  </span>
  methods<span class="token operator">?</span><span class="token punctuation">:</span> M <span class="token operator">&amp;</span> ThisType<span class="token operator">&lt;</span>D <span class="token operator">&amp;</span> M<span class="token operator">&gt;</span><span class="token punctuation">;</span>  
<span class="token punctuation">}</span>

<span class="token comment">// 这里定义一个mackObject函数，参数desc的类型为ObjectDescriptor&lt;D, M&gt;</span>
<span class="token keyword">function</span> makeObject<span class="token operator">&lt;</span>D<span class="token punctuation">,</span> M<span class="token operator">&gt;</span><span class="token punctuation">(</span>desc<span class="token punctuation">:</span> ObjectDescriptor<span class="token operator">&lt;</span>D<span class="token punctuation">,</span> M<span class="token operator">&gt;</span><span class="token punctuation">)</span><span class="token punctuation">:</span> D <span class="token operator">&amp;</span> M <span class="token punctuation">{</span> 
  <span class="token keyword">let</span> data<span class="token punctuation">:</span> object <span class="token operator">=</span> desc<span class="token punctuation">.</span>data <span class="token operator">||</span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">;</span>
  <span class="token keyword">let</span> methods<span class="token punctuation">:</span> object <span class="token operator">=</span> desc<span class="token punctuation">.</span>methods <span class="token operator">||</span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">;</span>
  <span class="token comment">// 这里通过...操作符，将data和methods里的所有属性、方法都放到了同一个对象里返回，这个对象的类型自然就      是D &amp; M，因为他同时包含D和M两个类型的字段  </span>
  <span class="token keyword">return</span> <span class="token punctuation">{</span> <span class="token operator">...</span>data<span class="token punctuation">,</span> <span class="token operator">...</span>methods <span class="token punctuation">}</span> <span class="token keyword">as</span> D <span class="token operator">&amp;</span> M<span class="token punctuation">;</span> 
<span class="token punctuation">}</span>

<span class="token keyword">let</span> obj <span class="token operator">=</span> <span class="token function">makeObject</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
  data<span class="token punctuation">:</span> <span class="token punctuation">{</span> x<span class="token punctuation">:</span> <span class="token number">0</span><span class="token punctuation">,</span> y<span class="token punctuation">:</span> <span class="token number">0</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token comment">// 这里data的类型就是我们上面定义ObjectDescriptor&lt;D, M&gt;类型中的D</span>
  methods<span class="token punctuation">:</span> <span class="token punctuation">{</span> <span class="token comment">// 这里methods的类型就是我们上面定义ObjectDescriptor&lt;D, M&gt;类型中的M</span>
    <span class="token function">moveBy</span><span class="token punctuation">(</span>dx<span class="token punctuation">:</span> <span class="token keyword">number</span><span class="token punctuation">,</span> dy<span class="token punctuation">:</span> <span class="token keyword">number</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
      <span class="token keyword">this</span><span class="token punctuation">.</span>x <span class="token operator">+=</span> dx<span class="token punctuation">;</span>  <span class="token comment">// 所以这里的this是我们通过ThisType&lt;D &amp; M&gt;指定的，this的类型就是D &amp; M</span>
      <span class="token keyword">this</span><span class="token punctuation">.</span>y <span class="token operator">+=</span> dy<span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

obj<span class="token punctuation">.</span>x <span class="token operator">=</span> <span class="token number">10</span><span class="token punctuation">;</span>
obj<span class="token punctuation">.</span>y <span class="token operator">=</span> <span class="token number">20</span><span class="token punctuation">;</span>
obj<span class="token punctuation">.</span><span class="token function">moveBy</span><span class="token punctuation">(</span><span class="token number">5</span><span class="token punctuation">,</span> <span class="token number">5</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre>
</div><div class="cl-preview-section"><p style="font-size: 20px; line-height: 38px;">(2) 不包含 ThisType&lt;T&gt; 指定的上下文类型，那么此时 this 具有上下文类型，也就是普通的情况。你可以试着把上面使用了 ThisType&lt;T&gt; 的例子中，ObjectDescriptor&lt;D, M&gt;类型中指定methods的类型中的 <code>&amp; ThisType&lt;D &amp; M&gt;</code> 去掉，你会发现 <code>moveBy</code> 方法中 <code>this.x</code> 和 <code>this.y</code> 报错了，因为此时 <code>this</code> 的类型是<code>methods</code> 这个对象字面量的类型。</p>
</div><div class="cl-preview-section"><h3 id="本节小结">本节小结</h3>
</div><div class="cl-preview-section"><p style="font-size: 20px; line-height: 38px;">本小节我们学习了this类型的相关知识，我们通过计数器的例子，学习了在1.7版本之后，编译器对有继承行为的类中this的类型的推断。还学习了对于对象的方法中，this指向的相关知识。更多的关于this类型的知识，可以看一下这个<a href="https://github.com/Microsoft/TypeScript/pull/14141">PR</a>中的介绍及例子，这里面完整地写了this的类型的规则。不过我们上面都举例学习了，总结一下：</p>
</div><div class="cl-preview-section"><ul>
<li style="font-size: 20px; line-height: 38px;">如果该方法具有显式声明的此参数，则该参数具有该参数的类型，也就是我们刚刚讲的例3.7.2；</li>
<li style="font-size: 20px; line-height: 38px;">否则，如果该方法由具有此参数的签名进行上下文类型化，则该参数具有该参数的类型，也就是我们讲的例3.7.1；</li>
<li style="font-size: 20px; line-height: 38px;">否则，如果在 tsconfig.json 里将 noImplicitThis 设为 true，且包含的对象文字具有包含 ThisType&lt;T&gt; 的上下文类型，则其类型为T，例子看我们讲的第(1)小点.</li>
<li style="font-size: 20px; line-height: 38px;">否则，如果启用了 --noImplicitThis 并且包含的对象文字具有不包含 ThisType&lt;T&gt; 的上下文类型，则它具有上下文类型，具体看我们讲的第(2)小点。</li>
<li style="font-size: 20px; line-height: 38px;">否则，this 的类型为 any 任何类型。</li>
</ul>
</div><div class="cl-preview-section"><p style="font-size: 20px; line-height: 38px;">下个小节我们将学习索引类型，这里说的索引类型，并不是前面我们讲接口的时候，给接口中字段名设置类型，我们将学习获取索引类型和索引值类型。<br>
<img src="http://img.mukewang.com/5d0345f40001410d16000296.jpg" alt="图片描述" data-original="http://img.mukewang.com/5d0345f40001410d16000296.jpg" class="" style="cursor: pointer;"></p>
</div></div>
            </div>
                            <!-- 买过的阅读 -->
                <div class="art-next-prev clearfix">
                                                                        <!-- 已买且开放 或者可以试读 -->
                            <a href="/read/35/article/356">
                                                    <div class="prev l clearfix">
                                <div class="icon l">
                                    <i class="imv2-arrow3_l"></i>
                                </div>
                                <p>
                                    19 使用可辨识联合并保证每个case都被处理
                                </p>
                            </div>
                        </a>
                                                                                            <!-- 已买且开放 或者可以试读 -->
                            <a href="/read/35/article/358">
                                                    <div class="next r clearfix">
                                <p>
                                    21 索引类型：获取索引类型和索引值类型
                                </p>
                                <div class="icon r">
                                    <i class="imv2-arrow3_r"></i>
                                </div>

                            </div>
                        </a>
                                    </div>
                    </div>
        <div class="comments-con js-comments-con" id="coments_con">
        </div>



    </div>
    
    
    

</div>
 
<!-- 专栏介绍页专栏评价 -->

<!-- 专栏介绍页底部三条评价 -->

<!-- 专栏阅读页弹层目录和介绍页页面目录 -->

<!-- 专栏阅读页发布回复 -->

<!-- 专栏阅读页发布评论 -->

<!-- 专栏阅读页底部评论 -->

<!-- 专栏阅读 单个 评论 -->

<!-- 新增回复和展开三条以外回复 -->

<!-- 立即订阅的弹窗 -->












</div></body></html>